/**
 * \file
 *           tlmRmtCfgSrvApp.cpp
 * \brief
 *           Implements tlmRmtCfgSrvApp class for Telematics
 *           this is the derived class from tlmServiceApp clas.
 *           It's the service class for remote configuration 
 *
 * \par Author (last changes):
 *          - Zeng Jie
 *          - BUIC, Continental Automotive Holdings Co., Ltd.
 * \par Project Leader:
 *          -
 * \par Responsible Developer:
 *          - Zeng Jie
 *          - BUIC, Continental Automotive Holdings Co., Ltd.
 * \par Responsible Architect:
 *          - Zhang Fa
 *          - BUIC, Continental Automotive Holdings Co., Ltd.
 *
 * \par Project:
 *      DPCA2
 *
 * \par SW-Component:
 *      Telematics
 *
 * \par SW-Package:
 *      Telematics
 *
 * \par SW-Module:
 *      Telematics Application
 *
 * \par SW-Architecture Specification:
 *      DPCA - TELEMATICS SW DD
 *      05b
 *
 * \par SW-Design Specification:
 *      DPCA - TELEMATICS SW DD
 *      05b
 *
 * \par SW-Test Case Specification:
 *
 * \par CM-Info:
 *
 * \note
 *      This is a note.
 *
 * \bug
 *      - there are no known bugs
 *
 * \par Module-History:
 *
 * \verbatim
 * Date                Author					Reason
 * 10 Dec 2013        Zeng Jie              Initial Creation
 * The latest entry at the head of the history list.
 * \endverbatim
 *
 * \par Copyright Notice:
 * Copyright (C) 2012 Continental Automotive Holdings Co., Ltd.
 * Alle Rechte vorbehalten. All Rights Reserved.\n
 * The reproduction, transmission or use of this document or its contents is
 * not permitted without express written authority.\n
 * Offenders will be liable for damages. All rights, including rights created
 * by patent grant or registration of a utility model or design, are reserved.
 *
 */
#include "stdafx.h"
#include "tlmRmtCfgSrvApp.h"
#include "tlmRmtCfgFactory.h"
//## operation OnReceiveMsg(tlmServiceMsg)
#include "tlmServiceMsg.h"
#include "tlmRmtCfgMsg.h"
#include "tlmRmtCfgSrvRpcSyncDesc.h"
#include "tlmRmtCfgSrvRpcAsyncDesc.h"
#include "teleLogTrace.h"

#include "ConnMgrApp.h"

#ifndef _RmtCfgStateEvt_h
#include "RmtCfgStateEvt.h"
#endif

extern HiGraphQueue gTeleQueue;


//## class tlmRmtCfgSrvApp
tlmRmtCfgSrvApp* tlmRmtCfgSrvApp::mpInstance;

/**
* \brief tlmRmtCfgSrvApp: this is constructor of tlmRmtCfgSrvApp class
*
* \note
*
* \param[in]
* - none
*
* \return
* - none
*/
tlmRmtCfgSrvApp::tlmRmtCfgSrvApp() : tlmServiceApp(), ActiveClass(), mAckStatus(TLM_ACK_STATUS_OK), mParaAdmin(),mParaNavi(),mParaWeb(){
}

/**
* \brief ~tlmRmtCfgSrvApp: this is destructor of tlmRmtCfgSrvApp class
*
* \note
*
* \param[in]
* - none
*
* \return
* - none
*/
tlmRmtCfgSrvApp::~tlmRmtCfgSrvApp() {
}

/**
* \brief GetAckStatus: get the ack status which indicates save parameters status
*
* \note
*
* \param[in]
* - none
*
* \return
* - uint8_t : ack status
*
* DesignID: MRN_TLM-SRV_SW_DD_113
*/
uint8_t tlmRmtCfgSrvApp::GetAckStatus() {
    return mAckStatus;
}

/**
* \brief GetInstance: retrieve or create new instace of tlmRmtCfgSrvApp
*
* \note
*
* \param[in]
* - none
*
* \return
* - tlmRmtCfgSrvApp*: pointer to tlmRmtCfgSrvApp instance
*
* DesignID: MRN_TLM-SRV_SW_DD_109
*/
tlmRmtCfgSrvApp* tlmRmtCfgSrvApp::GetInstance() {
    if(mpInstance == NIL)
    {
        mpInstance = new tlmRmtCfgSrvApp;
        LOG_PRINT(DPCA_TELE_MSGSRV_INFO,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>\n", __FUNCTION__);
    }
    return mpInstance;
}

/**
* \brief destroyInstance: destroy action when the object is delete.
*
* \note
*
* \param[in]
* - none
*
* \return
* - none
*
*/
void tlmRmtCfgSrvApp::destroyInstance(void)
{
    //LOG_PRINT(DPCA_TELE_MSGSRV_INFO,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>\n", __FUNCTION__);
}

/**
* \brief initialize: this function initialization the service app.
*
* \note
*
* \param[in]
* - none
*
* \return
* - none
*
*/
void tlmRmtCfgSrvApp::initialize(void)
{
    LOG_PRINT(DPCA_TELE_MSGSRV_INFO,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>\n", __FUNCTION__);
    //TODO:add initialization actions at here
}

/**
 *
 * \brief  This function perform the syncronize call of process handler class.
 *
 * \param p [in] Pointer of the data structure of RPC call
 *
 * \return - none
 */
void tlmRmtCfgSrvApp::__SyncCall(RPC_IOCTL_PTR p) {
    //#[ operation __SyncCall(RPC_IOCTL_PTR)
    tlmRmtCfgSrvRpcSyncDesc desc(p);
    desc.send(p->ac->mExecutionThread);
    //#]
}

/**
 * \brief  This function perform the Asyncronize call of process handler class.
 *
 * TestID: 
 *
 * \param p [in]  Pointer of the data structure of RPC call
 *
 * \return - none
 */
void tlmRmtCfgSrvApp::__AsyncCall(RPC_IOCTL_PTR p) {
    //#[ operation __AsyncCall(RPC_IOCTL_PTR)
    tlmRmtCfgSrvRpcAsyncDesc* pDesc = new tlmRmtCfgSrvRpcAsyncDesc(p);
    pDesc->send(p->ac->mExecutionThread);
    //#]
}




/**
* \brief GetParaAdmin : get the admin parameter object
*
* \note
*
* \param[in]
* - none
*
* \return
* - tlmRmtCfgParaAdmin* : pointer to admin parameter object
*
* DesignID: MRN_TLM-SRV_SW_DD_108
*/
tlmRmtCfgParaAdmin* tlmRmtCfgSrvApp::GetParaAdmin() {
    tlmRmtCfgParaAdmin * pParaAdmin = NIL;

    pParaAdmin = &mParaAdmin;
    return pParaAdmin;
}
/**
* \brief GetParaNavi : get the Navi parameter object
*
* \note
*
* \param[in]
* - none
*
* \return
* - tlmRmtCfgParaNavi* : pointer to Navi parameter object
*
* DesignID: MRN_TLM-SRV_SW_DD_107
*/
tlmRmtCfgParaNavi* tlmRmtCfgSrvApp::GetParaNavi() {
    tlmRmtCfgParaNavi * pParaNavi = NIL;

    pParaNavi = &mParaNavi;
    
    return pParaNavi;
}
/**
* \brief GetParaWeb : get the Web parameter object
*
* \note
*
* \param[in]
* - none
*
* \return
* - tlmRmtCfgParaWeb* : pointer to Web parameter object
*
* DesignID: MRN_TLM-SRV_SW_DD_106
*/
tlmRmtCfgParaWeb* tlmRmtCfgSrvApp::GetParaWeb() {
    tlmRmtCfgParaWeb * pParaWeb= NIL;

    pParaWeb = &mParaWeb;
    
    return pParaWeb;
}

/**
* \brief SaveParameters: Save parameters of remote configuration service
*
* \note
*
* \param[in]
* - none
*
* \return
* - uint8_t: save status
*
* DesignID: MRN_TLM-SRV_SW_DD_112
*/
uint8_t tlmRmtCfgSrvApp::SaveParameters() {
    uint8_t status=TLM_ACK_STATUS_OK;
    status = mParaWeb.Save(); 
    if(status == TLM_ACK_STATUS_OK)
    {  
    	status = mParaNavi.Save(); 
    }  
    
    if(status == TLM_ACK_STATUS_OK)
    {  
    	status = mParaAdmin.Save(); 
    } 
    
    return status;
    //#]
}
/**
* \brief SendMsg: send the messag to server 
*
* \note
*
* \param[in]
* - msg: pointer to message object that include the message which shall be send.
*
* \return
* - none
*
* DesignID: MRN_TLM-SRV_SW_DD_111
*/
void tlmRmtCfgSrvApp::SendMsg(tlmRmtCfgMsg* msg) const{ /*DG CPP2ISQP-ISQPcpp Rule 8.7.1-SCC_GRANT_0006*/
    if((mMsgHandler!=NIL) && (msg!=NIL))
    {
        //TODO:send message function should be implemented
    }
    else
    {
	    LOG_PRINT(DPCA_TELE_MSGSRV_ERROR,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, mMsgHandler[%d],msg[%d]\n", __FUNCTION__, mMsgHandler, msg);
    }
    //#]
}


void tlmRmtCfgSrvApp::tlmRmtCfgSrvApp_makeAsyncCall(DWORD funcId,DWORD* pData,DWORD size)
{
	LOG_PRINT(DPCA_TELE_tlmRmtCfgSrv_INFO,"[TELE]:tlmRmtCfgSrvApp::makeAsyncCall %d\n", funcId);
	s_RPC_IOCTL mIoCTL;

	/* RPC IOCTL stucture */
    mIoCTL.ac = this;
	mIoCTL.dmFuncID = static_cast<uc8_t>(funcId);
	mIoCTL.lpInBuffer = reinterpret_cast<LPVOID>(pData);
	mIoCTL.nInBufferSize = static_cast<uc8_t>(size);
	mIoCTL.lpOutBuffer = 0;
	mIoCTL.nOutBufferSize = 0;

	this->AsyncCall(&mIoCTL);
}

/**
* \brief OnReceiveMsg: this function is called when received message
* 
* \note
*
* \param[in]
* - srvMsg: pointere to serviceMsg object which is the received message
*
* \return
* - none
*
* DesignID: MRN_TLM-SRV_SW_DD_110
*/
void tlmRmtCfgSrvApp::OnReceiveMsg(tlmServiceMsg* srvMsg) {
    //#[ operation OnReceiveMsg(tlmServiceMsg)
    s_RPC_IOCTL lRpc;


	/* RPC IOCTL stucture */
	lRpc.ac = this;
	lRpc.dmFuncID = FUNCID_TLM_RMT_CFG_HANDLE_MSG;
	lRpc.lpInBuffer = reinterpret_cast<LPVOID *>(&srvMsg);
	lRpc.lpOutBuffer =  NIL;
	lRpc.nInBufferSize = static_cast<uc8_t>(sizeof(srvMsg));
	lRpc.nOutBufferSize = 0;


	this->AsyncCall(&lRpc);

    
    //__OnReceiveMsg(srvMsg);
    //#]
}

/**
* \brief __OnReceiveMsg:This function is the actual handler function to process the message 
*               it shall save the message if it's incoming traffic message
*               parse the data infomation section, and process it. 
* 
* \note
*
* \param[in]
* - none
*
* \return
* - none
*
* DesignID: MRN_TLM-SRV_SW_DD_102
*/
void tlmRmtCfgSrvApp::__OnReceiveMsg(tlmServiceMsg* srvMsg) {
	uint8_t msgType=0;
	BOOL retVal=TRUE;
    tlmRmtCfgMsg * pRmtCfgMsg=NIL;

    
    //all message pass to this function are incoming traffic message(srv type is 13)

    if(srvMsg==NIL)
    {
	    LOG_PRINT(DPCA_TELE_MSGSRV_ERROR,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, srvMsg is NIL\n", __FUNCTION__);
        retVal = FALSE;
    }
    else
    {
        LOG_PRINT(DPCA_TELE_MSGSRV_INFO,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, remote configuration service receive message\n", __FUNCTION__);

        msgType = srvMsg->GetMsgType();
        switch(msgType)
        {
            case TLM_MSG_TYPE_RMT_CFG_PENDING:
                {
                    //__OnReceivePendingMsg(srvMsg);
                    gTeleQueue.postEvent(EVT_RMTCFG_RcvPendingMsg, reinterpret_cast<uint32_t>(srvMsg));
                    break;    
                }

            case TLM_MSG_TYPE_RMT_CFG_REQUEST:
                {
                    //__OnReceiveReqParaMsg(srvMsg);
                    gTeleQueue.postEvent(EVT_RMTCFG_RcvReqParaMsg, reinterpret_cast<uint32_t>(srvMsg));
                    break; 
                }
            default:
                {
                    LOG_PRINT(DPCA_TELE_MSGSRV_ERROR,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, incorrect srv type[%d]\n", __FUNCTION__,msgType);
                    break;
                }
        }

        
        /*
        //create a new RmtCfgMsg instance
        pRmtCfgMsg = tlmRmtCfgFactory::GetInstance()->CreateSrvMsg(srvMsg->GetMsgBuf(), srvMsg->GetMsgLen());
    
        //#[ operation __OnReceiveMsg(tlmServiceMsg)
        //srvMsg->SaveMsg();
        //TODO:need save message at here

        //here can process the message
        retVal = srvMsg->HandleData(); 
        if(retVal)
        {
            srvMsg->GetMsgType(msgType);
            switch(msgType)
            {
                case TLM_MSG_TYPE_RMT_CFG_PENDING:
                    {
                        __OnReceivePendingMsg(srvMsg);
                        break;    
                    }

                case TLM_MSG_TYPE_RMT_CFG_REQUEST:
                    {
                        __OnReceiveReqParaMsg(srvMsg);
                        break; 
                    }

                case TLM_MSG_TYPE_RMT_CFG_SET_PARA:
                    {
                        __OnReceiveSetParaMsg(srvMsg);
                        break;    
                    }

                default:
                    {
                        break;
                    }
            }
        }
        else
        {
            LOG_PRINT(DPCA_TELE_MSGSRV_ERROR,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, Handle data failed\n", __FUNCTION__);
        }

        if(srvMsg!=NIL)
        {//here the message has been proceed, we need to delete it.
            delete srvMsg;
        }
        */
    }


    return;

    
    
    //#]
}

/**
* \brief __OnReceivePendingMsg: this function is used to process pending(27) message
*                   it create con(29) message, fill it and send it to server
*
* \note
*
* \param[in]
* - srvMsg: pointer to message which should be pending message
*
* \return
* - none
*
* DesignID: MRN_TLM-SRV_SW_DD_103
*/
void tlmRmtCfgSrvApp::__OnReceivePendingMsg(tlmRmtCfgMsg* srvMsg) const{
    //#[ operation __OnReceivePendingMsg(tlmRmtCfgMsg)
    //Received an pending message(mstType:0x27), need send connection message to offboard server.
    

    tlmRmtCfgMsg* pConMsg=NIL;
    pConMsg = tlmRmtCfgFactory::GetInstance()->CreateSrvMsg(TLM_SRV_TYPE_REMOTE_CONFIG,TLM_MSG_TYPE_RMT_CFG_CONNECT);
    
    if(pConMsg!=NIL)
    {
        pConMsg->Init();
        pConMsg->Fill();
        SendMsg(pConMsg);
    }
    
    //#]
}
void tlmRmtCfgSrvApp::CheckNewPendMsg(tlmServiceMsg* srvMsg) {
    //This function shall be called when receive pending message while the previous set config procss has not completed.
    uint16_t newMsgId = 0;
    uint16_t curMsgId = 0;

    newMsgId = srvMsg->GetMsgUniqueId();
    curMsgId = mCurSrvMsg->GetMsgUniqueId();

    if(newMsgId != curMsgId)
    {//received message is different with the current one 
        gTeleQueue.postEvent(EVT_RMTCFG_RcvNewPendingMsg, reinterpret_cast<uint32_t>(srvMsg));
    }
}
void tlmRmtCfgSrvApp::HandlePendingMsg(tlmRmtCfgMsg* srvMsg) {
    tlmRmtCfgMsg* pConMsg=NIL;
    pConMsg = tlmRmtCfgFactory::GetInstance()->CreateSrvMsg(TLM_SRV_TYPE_REMOTE_CONFIG,TLM_MSG_TYPE_RMT_CFG_CONNECT);
    
    if(pConMsg!=NIL)
    {
        pConMsg->Init();
        pConMsg->Fill();

        gTeleQueue.postEvent(EVT_RMTCFG_ReqConnection, NIL);
    }
}

void tlmRmtCfgSrvApp::OnReqConnection(void) {

    E_CONN_STATUS status;

    ConnMgrApp* pConnMgrApp = const_cast<ConnMgrApp*>(&(ConnMgrApp::getInstance()));
    if(pConnMgrApp)
    {
        //TODO: the mSetSessionId is not enough, there should be getsessionID, need to think about it.
        if(mSetSessionId == 0)
        {//has not request network, need to set up it.
            pConnMgrApp->onReqConnection(tlmSrcTlm,&mSetSessionId,&status);
        }
        else
        {//the request has been done, no need to set up it again
            status = pConnMgrApp->getConnectionState();
        }

        if(status != CS_CONNECTED)
        {
            gTeleQueue.postEvent(EVT_RMTCFG_WaitConnAvailable, NIL);
        }
        else
        {
            gTeleQueue.postEvent(EVT_RMTCFG_ConnAvailable, NIL);
        }

        
    }
    else
    {
	    LOG_PRINT(DPCA_TELE_MSGSRV_ERROR,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, ConnMgrApp instance is NIL\n", __FUNCTION__);
    }



}
/**
* \brief __OnReceiveReqParaMsg: this function is used to process reqPara(28) message
*               it get current configuration if it's requested, then create sendPara(31)
*               message and send it to server
*
* \note
*
* \param[in]
* - srvMsg: pointer to message which should be reqPara message
*
* \return
* - none
*
* DesignID: MRN_TLM-SRV_SW_DD_104
*/
void tlmRmtCfgSrvApp::__OnReceiveReqParaMsg(tlmRmtCfgMsg* srvMsg) {
    //#[ operation __OnReceiveReqParaMsg(tlmRmtCfgMsg)
    //Received an pending message(mstType:0x28), need send parameters message to offboard server.
    tlmRmtCfgParaWeb *pParaWeb = NIL;     
    tlmRmtCfgParaNavi *pParaNavi = NIL;
    tlmRmtCfgParaAdmin *pParaAdmin = NIL; 

    if(NIL == srvMsg)
    {
	    LOG_PRINT(DPCA_TELE_MSGSRV_ERROR,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, srvMsg is NIL\n", __FUNCTION__);
    }
    else
    {
        LOG_PRINT(DPCA_TELE_MSGSRV_INFO,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, receive reqPara message\n", __FUNCTION__);
        //check if the parameters is requested to send
        pParaWeb = srvMsg->GetParaWeb();
        if(pParaWeb!=NIL)
        {
            mParaWeb.SetRequested(pParaWeb->IsRequested());  
            pParaWeb->ClearRequested();
        } 

        //check if the parameters is requested to send
        pParaNavi = srvMsg->GetParaNavi();
        if(pParaNavi!=NIL)
        {
            mParaNavi.SetRequested(pParaNavi->IsRequested());
            pParaNavi->ClearRequested();
        } 

        //check if the parameters is requested to send
        pParaAdmin = srvMsg->GetParaAdmin();
        if(pParaAdmin!=NIL)
        {   
            //set the current para flag
            mParaAdmin.SetRequested(pParaAdmin->IsRequested()); 

            //clear the component in message.
            pParaAdmin->ClearRequested();
        } 


        //SetupHttpConnection();  

        tlmRmtCfgMsg* pSendParaMsg=NIL;
        pSendParaMsg = tlmRmtCfgFactory::GetInstance()->CreateSrvMsg(TLM_SRV_TYPE_REMOTE_CONFIG,TLM_MSG_TYPE_RMT_CFG_SEND_PARA);

        if(pSendParaMsg!=NIL)
        {    
            pSendParaMsg->SetItsService(this);
            pSendParaMsg->Init();
            pSendParaMsg->Fill();
            SendMsg(pSendParaMsg);

            //TODO: shall delete sendPara message after send successfully.
        }         
        else
        {
            LOG_PRINT(DPCA_TELE_MSGSRV_ERROR,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, create sendPara message failed\n", __FUNCTION__);
        }

        //After send the message, shall clear the requested flag.
        mParaWeb.ClearRequested();
        mParaNavi.ClearRequested();
        mParaAdmin.ClearRequested();

    }

    //#]
}

/**
* \brief __OnReceiveSetParaMsg: this function is used to process setPara(30) message
*           it update current configuration, and save it into NVM
*
* \note
*
* \param[in]
* - srvMsg: pointer to message which should be setPara message
*
* \return
* - none
*
* DesignID: MRN_TLM-SRV_SW_DD_105
*/
void tlmRmtCfgSrvApp::__OnReceiveSetParaMsg(tlmRmtCfgMsg* srvMsg) {
    //#[ operation __OnReceiveSetParaMsg(tlmRmtCfgMsg)
    //Received an set para message(mstType:0x30), need update the configuration parameters.  
    
    //the parameters has been parsed in srvMsg, we just need to update it. 
    
    tlmRmtCfgParaWeb *pParaWeb = NIL;     
    tlmRmtCfgParaNavi *pParaNavi = NIL;
    tlmRmtCfgParaAdmin *pParaAdmin = NIL;

    if(NIL == srvMsg)
    {
	    //LOG_PRINT(DPCA_TELE_MSGSRV_ERROR,"[TLM_MSGSRV]:<tlmRmtCfgSrvApp::%s>, srvMsg is NIL\n", __FUNCTION__);
    }
    else
    {

        //update the web parameters
        pParaWeb = srvMsg->GetParaWeb();
        if(pParaWeb!=NIL)
        {
            mParaWeb.Update(pParaWeb);
        } 

        //update the navi parameters  
        pParaNavi = srvMsg->GetParaNavi();
        if(pParaNavi!=NIL)
        {
            mParaNavi.Update(pParaNavi);
        }  

        //update the Admin parameters
        pParaAdmin = srvMsg->GetParaAdmin();
        if(pParaAdmin!=NIL)
        {
            mParaAdmin.Update(pParaAdmin);
        }       

        mAckStatus=SaveParameters();  
        //After update message, we shall send Ack message to offboard server.  

        //SetupHttpConnection();  

        tlmRmtCfgMsg* pAckMsg=NIL;
        pAckMsg = tlmRmtCfgFactory::GetInstance()->CreateSrvMsg(TLM_SRV_TYPE_REMOTE_CONFIG,TLM_MSG_TYPE_RMT_CFG_ACK);

        if(pAckMsg!=NIL)
        {    
            pAckMsg->SetItsService(this);
            pAckMsg->Init();
            pAckMsg->Fill();
            SendMsg(pAckMsg);
        }

    }
    //#]
}
